/*
 *
 *  Copyright (C) 2010 Tal Eisenberg
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package tal.drivechain.chain.shell;

import tal.drivechain.chain.Chain;
import tal.drivechain.module.xmlconfig.PropertyInfo;
import tal.drivechain.parsing.Tokenizer;
import tal.drivechain.variable.VarTable;
import tal.drivechain.variable.VarTableAction;
import tal.drivechain.variable.Variable;

/**
 *
 * @author eisental
 */
public class VariableObject extends ShellObject {

    public VariableObject(DriveShell shell) { super("variable", "variables", "var", shell); }

    @Override
    public boolean isActionSupported(Action action) {
        return true;
    }

    @Override
    public void make(String command) throws IllegalArgumentException {
        boolean pubvar = false;
        if (command.startsWith("public ")) {
            pubvar = true;
            command = command.substring(7);
        }

        if (command.length()==0) throw new IllegalArgumentException("Variable definition is missing from command.");
        
        Chain c = shell.getActiveChain();

        Variable var = prepareNewVariable(command);
        if (var.getName().equals("$new$"))
            throw new IllegalArgumentException("Variable name is missing from definition.");
        if (!pubvar) {
            c.storeChainVar(var.getName(), var);
        } else {
            c.storePublicVar(var.getName(), var);
        }
        out.println("Created variable " + var + " as a " + (pubvar?"public ":"") + "variable of chain " + shell.getActiveChain().getName());
    }

    @Override
    public void remove(String command) throws IllegalArgumentException {
        Chain c = shell.getActiveChain();
        if (c.getVarTable().containsKey(command)) {
            c.getVarTable().remove(command);

            PropertyInfo propToRemove = null;
            for (PropertyInfo p : c.getNodeInfo().getProperties())
                if (p.getName().equals(command))
                    propToRemove = p;
            if (propToRemove!=null) c.getNodeInfo().getProperties().remove(propToRemove);

            out.println("variable " + command + " was removed from the chain.");
        } else {
            out.println("variable " + command + " does not exist.");
        }
    }

    public void rename(String command) throws IllegalArgumentException {
        // rename var x to y
        Chain c = shell.getActiveChain();
        String[] split = command.split("\\sto\\s");
        if (split.length!=2) throw new IllegalArgumentException("Invalid syntax. Expecting rename var <old-name> to <new-name>");
        String oldName = split[0], newName = split[1];

        if (c.getVarTable().containsKey(oldName)) {
            Variable v = c.getVarTable().get(oldName);
            v.setName(newName);
            c.getVarTable().remove(oldName);
            c.getVarTable().put(newName, v);
            out.println("Renamed variable" + oldName + ": " + c.getVarTable().get(newName).toString());
        } else out.println("Variable " + oldName + " does not exist.");
    }

    @Override
    public void set(String command) throws IllegalArgumentException {
        String[] words = new Tokenizer(command, ' ').getTokens();
        if (words.length!=2)
            throw new IllegalArgumentException("Invalid syntax (should be: set variable <var identifier> <var definition>");

        Variable var = prepareNewVariable(words[1]);
        VarTableAction setVar = VarTableAction.parseAction(VarTableAction.Action.SET_EXISTING, words[0]);

        VarTable chainVars = shell.getActiveChain().getVarTable();

        boolean pubvar = chainVars.isPublicVar(setVar.getName());

        if (chainVars.containsKey(setVar.getName()))
            setVar.set(var, chainVars, shell.getActiveChain());
        out.println("Set " + (pubvar?"public ":"") + setVar.getLookupString() + " to " + var.getValueDefinition(shell.getActiveChain()));
    }

    @Override
    public void list() throws IllegalArgumentException {
        out.println(InfoPrinter.printVarTable(shell.getActiveChain().getVarTable()));
    }

    @Override
    public void inspect(String command) throws IllegalArgumentException {
        if (command==null || command.length()==0) throw new IllegalArgumentException("Invalid syntax. Expecting: inspect var <var-name>");

        Variable var = shell.getActiveChain().findVariable(command);
        if (var==null) throw new IllegalArgumentException("Variable " + command + " does not exist in chain " + shell.getActiveChain().getPath());
        out.println((shell.getActiveChain().getVarTable().isPublicVar(var.getName())?"public ":"") + var.toString(null) + " value: " + var.getDataType().toString(var.getInternalValue(), shell.getActiveChain()));
    }

    public Variable prepareNewVariable(String def) {
        return Variable.parseVariable("$new$", null, def, false);
    }
}
